#include <arpa/inet.h>
#include <QDebug>
#include <QFile>
#include <QUdpSocket>
#include <QByteArray>
#include "request.h"

#define RECV_TIMEOUT 5
#define RECV_RETRIES 5

Request::Request(MainWindow *window, QString filename, OpCode oc, TransMode tm) : QThread(window)
{
    this->mOc = oc;
    this->mTm = tm;
    this->mFileName = filename;
    this->mWindow = window;
}

void Request::setFilePath(QString path)
{
    mFilePath = path;
}

void Request::setRrid(int rrid)
{
    mRrid = rrid;
}

void Request::setDestination(const QHostAddress address, quint16 port)
{
    mPort = port;
    mAddress = address;
}

void progress(int rowid, quint64 trans, quint64 total)
{

}

void Request::handleReadReq()
{
    qint64 len;
    uint16_t bn = 0;
    Message msg;
    QFile *file;
    QUdpSocket *sock;

    qDebug() << "Handle read request :" << mFileName;

    sock = new QUdpSocket();
    file = new QFile(mFilePath);

    if (!file->open(QIODevice::ReadOnly))
    {
        qDebug() << "File open error :" << mFileName;
        return;
    }

    while (true)
    {
        if (file->atEnd())
        {
            qDebug() << "Handle read request done :" << mFileName;
            break;
        }

        /* seek to block position */
        file->seek(bn * sizeof(msg.data.data));
        emit progress(mRrid, file->pos(), file->size());

        /* read block data */
        if ((len = file->read(msg.data.data, sizeof(msg.data.data))) < 0)
        {
            qDebug() << "Read file error :" << mFileName;
            break;
        }

        len = len + 4;
        msg.data.opcode = htons(OC_DATA);
        msg.data.block_number = htons(bn + 1);

        /* send block data */
        for (int i = 0; i < RECV_RETRIES; i++)
        {
            if (sock->writeDatagram((const char *)&msg, len, mAddress, mPort) != len)
            {
                qDebug() << "Write data error";
                continue;
            }

            /* 1. read data */
            if (!sock->waitForReadyRead(3000))
            {
                qDebug() << "Wait ack error";
                continue;
            }

            if (sock->readDatagram((char *)&msg, sizeof(msg)) != 4)
            {
                qDebug() << "Invalid ack message";
                continue;
            }

            if (msg.opcode == htons(OC_ACK))
            {
                bn = ntohs(msg.ack.block_number);
                break;
            }
        }
    }
}

void Request::handleWriteReq()
{
    qDebug() << "Handle write request :" << mFileName;
}

void Request::run()
{
    if (mOc == OC_RRQ)
        handleReadReq();
    else if (mOc == OC_WRQ)
        handleWriteReq();
    else
        qCritical() << "Invalid opcode" << mOc << "from" << mAddress.toString() << endl;
}
